home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / circuits / irsim-ca.2 / irsim-ca / irsim-cap-9.2 / src / ana11 / postscript.c < prev    next >
C/C++ Source or Header  |  1995-05-29  |  17KB  |  654 lines

  1. /*
  2.  *     ********************************************************************* 
  3.  *     * Copyright (C) 1988, 1990 Stanford University.                     * 
  4.  *     * Permission to use, copy, modify, and distribute this              * 
  5.  *     * software and its documentation for any purpose and without        * 
  6.  *     * fee is hereby granted, provided that the above copyright          * 
  7.  *     * notice appear in all copies.  Stanford University                 * 
  8.  *     * makes no representations about the suitability of this            * 
  9.  *     * software for any purpose.  It is provided "as is" without         * 
  10.  *     * express or implied warranty.  Export of this software outside     * 
  11.  *     * of the United States of America may require an export license.    * 
  12.  *     *********************************************************************
  13.  */
  14.  
  15. #include <pwd.h>
  16.  
  17. #include <stdio.h>
  18. #include <sys/types.h>
  19. #include <time.h>
  20. #include "ana.h"
  21. #include "ana_glob.h"
  22.  
  23.  
  24. #define    DATE_LEN    25    /* length of ascii date returned by ctime */
  25.  
  26.  
  27. private int    psBanner = TRUE;
  28. private int    psLegend = FALSE;
  29. private int    psTimes = TRUE;
  30. private int    psOutline = TRUE;
  31.  
  32.  
  33. private    void   WritePSfile(), DrawOutline(), PrintNames(), PrintTraces();
  34. private    void   PrintSignal(), PrintVector(), PrintTimes(), PrintLegend();
  35.  
  36.  
  37. public void SetPSParms( s )
  38.   char  *s;
  39.   {
  40.     int  *parm;
  41.  
  42.     switch( s[1] )
  43.       {
  44.     case 'b' :
  45.         psBanner ^= TRUE;
  46.         break;
  47.     case 'l' :
  48.         psLegend ^= TRUE;
  49.         break;
  50.     case 't' :
  51.         psTimes ^= TRUE;
  52.         break;
  53.     case 'o' :
  54.         psOutline ^= TRUE;
  55.         break;
  56.       }
  57.     if( *s == MENU_UNMARK )
  58.     *s = MENU_MARK;
  59.     else
  60.     *s = MENU_UNMARK;
  61.   }
  62.  
  63.  
  64. typedef enum { black, white, gray, xpat } pattern;
  65. private    char      fname[256] = "";
  66. private    FILE      *psout;
  67. private    pattern   currPat;
  68.  
  69.  
  70. public void printPS( s )
  71.   char *s;
  72.   {
  73.     if( traces.disp == 0 or tims.first >= tims.last )
  74.       {
  75.     PRINT( "\nThere's nothing to print" );
  76.     XBell( display, 0 );
  77.     return;
  78.       }
  79.     if( *fname == '\0' )
  80.       {
  81.     (void) strncpy( fname, banner, bannerLen );
  82.     fname[bannerLen] = '\0';
  83.     (void) strcat( fname, ".ps" );
  84.       }
  85.     PRINTF( "\nEnter filename (%s)", fname );
  86.     Query( " > ", WritePSfile );
  87.   }
  88.  
  89.  
  90. private void WritePSfile( psfname )
  91.   char  *psfname;
  92.   {
  93.  
  94. /*    struct passwd *pass ;
  95.     char    *UserName;
  96.     char    *tmp;
  97.     int     UserNameLength;
  98. */
  99.  
  100.     char    *date;
  101.     time_t  theTime, time();
  102.  
  103.     if( psfname == NULL )
  104.     return;
  105.  
  106.     if( *psfname == '\0' )
  107.     psfname = fname;
  108.     else
  109.     (void) strcpy( fname, psfname );
  110.  
  111.     if( (psout = fopen( psfname, "w" )) == NULL )
  112.       {
  113.     PRINTF( "\ncan't open '%s' for output", psfname );
  114.     return;
  115.       }
  116.     PRINTF( "\nWriting %s...", psfname );
  117.     XDefineCursor( display, window, cursors.timer );
  118.     XFlush( display );
  119.  
  120.     currPat = black;
  121.     WritePreamble();
  122.     theTime = time( 0 );
  123.     date = ctime( &theTime );
  124.  
  125. /*    pass = getpwuid(getuid()) ;
  126.     UserName = tmp = pass->pw_name;
  127.  
  128.     for (UserNameLength=0; *tmp != '\0'; tmp++ ) UserNameLength++ ;
  129.  
  130.     printf(" date= %s,   USER= %s, UserLength= %d \n",date,UserName  ,UserNameLength ); 
  131. */
  132.  
  133.     fprintf( psout, "MSAVE\n" );
  134.     DrawOutline( date );
  135.     if( psTimes )
  136.     PrintTimes( tims.start, tims.end );
  137.     PrintNames();
  138.     PrintTraces( tims.start, min( tims.end, tims.last ) );
  139.     fprintf( psout, "showpage MRESTORE\n" );
  140.  
  141.     if( psLegend )
  142.       {
  143.     DrawOutline( date );
  144.     PrintLegend();
  145.     fprintf( psout, "showpage\n" );
  146.       }
  147.     (void) fclose( psout );
  148.     PRINT( "done" );
  149.     XDefineCursor( display, window, cursors.deflt );
  150.   }
  151.  
  152.  
  153.     /* Macros to Convert from screen to PostScript units */
  154.  
  155. #define    PS_UNITS    72            /* PostScript unit (1/inch) */
  156. #define    ps_YSIZE    (15 * PS_UNITS / 2)    /* y page size = 7.5 inch */
  157. #define    ps_XSIZE    (10 * PS_UNITS)        /* x page size = 10 inch */
  158. #define    XMARGIN        (PS_UNITS / 2)        /* margins 1/2 inch */
  159. #define    YMARGIN        (PS_UNITS / 2)
  160. #define    FSIZE        9            /* default font size */
  161. #define    MINFSIZE    4            /* minimum font size */
  162. #define    LEGFSIZE    7            /* legend font size */
  163.  
  164. #define    YTRACE        (traceBox.bot - traceBox.top + 1)
  165. #define    TIMES_HEIGHT    20
  166. #define    BANNER_HEIGHT    15
  167. #define    psHEIGHT    ( ps_YSIZE - TIMES_HEIGHT - BANNER_HEIGHT )
  168.  
  169.         /* scale conversion macros */
  170. #define    PSX( x )    ( (x) * (ps_XSIZE - 2) / traceBox.right )
  171. #define    PSY( y )    ( (YWINDOWSIZE - (y)) * psHEIGHT / YTRACE )
  172. #define    PS( x, y )    PSX( x ), PSY( y )
  173.  
  174. #define    BANNER_BOT    ( psHEIGHT + PSY( traceBox.bot ) )
  175. #define BANNER_TOP    ( BANNER_BOT + BANNER_HEIGHT )
  176. #define BANNER_MID    ( (BANNER_TOP + BANNER_BOT + 1) / 2 )
  177.  
  178. #define    TIMES_TOP    PSY( traceBox.bot )
  179. #define    TIMES_BOT    (TIMES_TOP - TIMES_HEIGHT )
  180.  
  181.  
  182. /**************************************************************************/
  183. /*    Redefine the graphics operators to generate the PostScript code   */
  184. /**************************************************************************/
  185.  
  186. #define    BLACK        1        /* anything will do */
  187. #define    WHITE        0
  188.  
  189. #define    VLine( X, BOT, TOP, COLOR )                    \
  190.     fprintf( psout, "%d %d %d VL\n", PS( X, BOT), PSY( TOP ) );
  191.  
  192. #define    HLine( LEFT, RIGHT, Y, COLOR )                    \
  193.     fprintf( psout, "%d %d %d HL\n", PS( LEFT, Y ), PSX( RIGHT ) );
  194.  
  195. #define    Line( X1, Y1, X2, Y2 )                        \
  196.     fprintf( psout, "%d %d %d %d L\n", PS( X1, Y1 ), PS( X2, Y2 ) );
  197.  
  198. #define FillAREA( X, Y, WIDTH, HEIGHT, COLOR )                \
  199.   {                                    \
  200.     pattern  opatt = SetPattern( COLOR );                \
  201.     fprintf( psout, "%d %d %d %d BOX fill\n", PS( X, Y ),        \
  202.       PS( (X) + (WIDTH) - 1, (Y) + (HEIGHT) - 1 ) );            \
  203.     (void) SetPattern( opatt );                        \
  204.   }                                    \
  205.  
  206.  
  207. #define StrLeft( S, LEN, LEFT, BOT, FG, BG )                \
  208.   {                                    \
  209.     psString( S, LEN );                            \
  210.     fprintf( psout, "%d %d SL\n", PS( LEFT, BOT ) );            \
  211.   }                                    \
  212.  
  213.  
  214. #define StrRight( S, LEN, RIGHT, MID, FG, BG )                \
  215.   {                                    \
  216.     psString( S, LEN );                            \
  217.     fprintf( psout, "%d %d SR\n", PS( RIGHT, MID ) );            \
  218.   }                                    \
  219.  
  220.  
  221. #define StrCenter( S, LEN, LEFT, RIGHT, MID, FG, BG )            \
  222.   {                                    \
  223.     psString( S, LEN );                            \
  224.     fprintf( psout, "%d %d %d SC\n", PSX( LEFT ), PS( RIGHT, MID ) );    \
  225.   }                                    \
  226.  
  227.  
  228. /**************************************************************************/
  229.  
  230. /*
  231.  * Write out an string, prepending parens with '\'
  232.  */
  233. private void psString( s, len )
  234.   char  *s;
  235.   int   len;
  236.   {
  237.     putc( '(', psout );
  238.     while( *s != '\0' and len != 0 )
  239.       {
  240.     if( (*s == '(' ) || (*s == ')') )
  241.         putc( '\\', psout );
  242.         putc( *s, psout );
  243.     s++;
  244.     len--;
  245.       }
  246.     putc( ')', psout );
  247.   }
  248.  
  249.  
  250. private pattern SetPattern( patt )
  251.   pattern  patt;
  252.   {
  253.     float    grayscale;
  254.     pattern  ret;
  255.  
  256.     if( patt == white )
  257.     grayscale = 1.0;
  258.     else if( patt == gray )
  259.     grayscale = 0.82;
  260.     else if( patt == xpat )
  261.     grayscale = 0.68;
  262.     else /* black */
  263.     grayscale = 0.0;
  264.     fprintf( psout, "%g setgray\n", grayscale );
  265.     ret = currPat;
  266.     currPat = patt;
  267.     return( ret );
  268.   }
  269.  
  270.  
  271. private void DrawOutline( date )
  272.   char  *date;
  273.   {
  274.     pattern  opatt;
  275.     char     info[ 256 ];
  276.  
  277.     struct passwd *pass ;
  278.     char    *UserName;
  279.     char    *tmp;
  280.     int     UserNameLength;
  281.  
  282.     pass = getpwuid(getuid()) ;
  283.     UserName = tmp = pass->pw_name;
  284.  
  285.     for (UserNameLength=0; *tmp != '\0'; tmp++ ) UserNameLength++ ;
  286.  
  287.  
  288.     if( psBanner )
  289.       {
  290.     opatt = SetPattern( gray );
  291.     fprintf( psout, "%d %d %d %d BOX fill \n", 0, BANNER_BOT, ps_XSIZE, BANNER_TOP);
  292.     (void) SetPattern( opatt );
  293.     fprintf (psout, "%d %d %d %d BOX stroke \n", 0, BANNER_BOT, ps_XSIZE, BANNER_TOP);
  294.  
  295.     (void) sprintf( info, "USER:%s", UserName);
  296.     psString( info, UserNameLength + 5 );
  297.     fprintf( psout, "%d %d FSIZE 2 div sub SL\n", 6, BANNER_MID );
  298.  
  299.     (void) sprintf( info, "FILE:%s", banner);
  300.     psString( info, bannerLen + 5 );
  301.     fprintf( psout, "%d %d FSIZE 2 div sub SL\n", 
  302.          (int) PSX( traceBox.right - 4 ) / 2, 
  303.         BANNER_MID );
  304.  
  305.     if( strncmp( banner, fname, bannerLen ) != 0 )
  306.       {
  307.         (void) sprintf( info, "(%s)  %s", fname, date );
  308.         psString( info, bannerLen + DATE_LEN );
  309.       }
  310.     else
  311.         psString( date, DATE_LEN );
  312.     fprintf( psout, " %d %d SR\n", PSX( traceBox.right - 4 ), BANNER_MID);
  313.       }
  314.     if( psOutline )
  315.              fprintf( psout, "%d %d %d %d BOX stroke \n", 0, TIMES_BOT, ps_XSIZE, BANNER_TOP);
  316.   }
  317.  
  318.  
  319.  
  320.     /* FactorTbl: time grid at multiples of 1/FactorTbl => .1 .5 .25 1 */
  321. private    int    FactorTbl[] = { 10, 2, 4, 1};
  322.  
  323. private void PrintTimes( t1, t2 )
  324.   TimeType t1, t2;
  325.   {
  326.     TimeType  step, half_step, i;
  327.     int       x;
  328.     char      s[ 25 ];
  329.  
  330.     for( step = tims.steps, i = 1; step >= 10; step /= 10, i *= 10 );
  331.     for( x = 0; ; x++ )
  332.       {
  333.     int nsteps = tims.steps /( i / FactorTbl[x] );
  334.     if( nsteps > 5 and nsteps < 15 )
  335.         break;
  336.       }
  337.     step = i / FactorTbl[x];
  338.     half_step = ( step > 2 ) ? (step / 2) - 1 : 2;
  339.  
  340.     fprintf( psout, "0 setlinewidth [1 3] 0 setdash /svfnt currentfont def\n");
  341.     fprintf( psout, "theFont 0.7 FSIZE mul scalefont setfont\n" );
  342.     psString( "time (ns)", 30 );
  343.     fprintf( psout, " %d %d %d SC\n", 0, PSX(traceBox.left) - 1, TIMES_TOP );
  344.  
  345.     i = ((t1 + step - 1) / step) * step;
  346.     if( i != t1 )
  347.       {
  348.     x = TimeToX( t1 );
  349.     VLine( x, traceBox.top, traceBox.bot + 3, BLACK );
  350.     if( i - t1 >= half_step )
  351.       {
  352.         (void) sprintf( s, "%.1f", d2ns( t1 ) );
  353.         x = 2 * PSX( x );
  354.         fprintf( psout, "(%s) 0 %d %d SC\n", s, x, (TIMES_BOT+TIMES_TOP)/2 );
  355.       }
  356.       }
  357.  
  358.     while( i <= t2 )
  359.       {
  360.     x = TimeToX( i );
  361.     VLine( x, traceBox.top, traceBox.bot + 3, BLACK );
  362.     (void) sprintf( s, "%.1f", d2ns( i ) );
  363.     x = 2 * PSX( x );
  364.     fprintf( psout, "(%s) 0 %d %d SC\n", s, x, (TIMES_BOT+TIMES_TOP)/2 );
  365.     i += step;
  366.       }
  367.  
  368.     if( i > t2 and (t2 - i + step) >= half_step )
  369.       {
  370.     x = TimeToX( t2 );
  371.     VLine( x, traceBox.top, traceBox.bot + 3, BLACK );
  372.     (void) sprintf( s, "%.1f", d2ns( t2 ) );
  373.     x = PSX( x );
  374.     fprintf( psout, "(%s) %d %d SR\n", s, x, (TIMES_BOT+TIMES_TOP)/2 );
  375.       }
  376.  
  377.     HLine( traceBox.left - 2, traceBox.right, traceBox.bot, BLACK );
  378.     fprintf( psout, "0.6 setlinewidth [] 0 setdash svfnt setfont\n" );
  379.   }
  380.  
  381.  
  382. private void PrintNames()
  383.   {
  384.     Coord         x, y;
  385.     TraceEnt      *t;
  386.     int           i;
  387.  
  388.     x = namesBox.right - 2;
  389.     for( t = traces.first, i = traces.disp; i != 0; i--, t = t->next )
  390.       {
  391.     y = (t->bot + t->top) / 2;
  392.     StrRight( t->name, t->len, x, y, BLACK, WHITE );
  393.       }
  394.   }
  395.  
  396.  
  397. private void PrintTraces( t1, t2 )
  398.   TimeType  t1,t2;
  399.   {
  400.     Trptr  t;
  401.     int    nt;
  402.  
  403.     for( t = traces.first, nt = traces.disp; nt != 0; nt--, t = t->next )
  404.       {
  405.     if( IsVector( t ) )
  406.         PrintVector( t, t1, t2 );
  407.     else
  408.         PrintSignal( t, t1, t2 );
  409.       }
  410.   }
  411.  
  412.  
  413. private void PrintSignal( t, t1, t2 )
  414.   Trptr              t;
  415.   register TimeType  t1, t2;
  416.   {
  417.     register hptr  h;
  418.     register int   val, change;
  419.     int            x1, x2;
  420.  
  421.     if( t1 >= tims.last )
  422.     return;
  423.  
  424.     h = t->cache[0].wind;
  425.  
  426.     x1 = TimeToX( t1 );
  427.     while( t1 < t2 )
  428.       {
  429.     val = h->val;
  430.     while( h->time < t2 and h->val == val )
  431.         NEXTH( h, h );
  432.  
  433.     if( h->time > t2 )
  434.       {
  435.         change = FALSE;
  436.         t1 = t2;
  437.       }
  438.     else
  439.       {
  440.         change = ( h->val != val );
  441.         t1 = h->time;
  442.       }
  443.     x2 = TimeToX( t1 );
  444.     switch( val )
  445.       {
  446.         case LOW :
  447.         HLine( x1, x2, t->bot, WHITE );
  448.         break;
  449.         case HIGH :
  450.         HLine( x1, x2, t->top, WHITE );
  451.         break;
  452.         case X :
  453.         FillAREA( x1, t->top, x2 - x1 + 1, t->bot - t->top + 1, xpat );
  454.         if( x1 > traceBox.left + 1 )
  455.             VLine( x1, t->bot, t->top, WHITE );
  456.         break;
  457.       }
  458.     if( change )
  459.         VLine( x2, t->bot, t->top, WHITE );
  460.     x1 = x2;
  461.       }
  462.   }
  463.  
  464.  
  465. private void PrintVector( t, t1, t2 )
  466.   register Trptr     t;
  467.   register TimeType  t1, t2;
  468.   {
  469.     hptr      *start, *changes;
  470.     TimeType  firstChange;
  471.     int       x1, x2, xx, mid, nbits, strlen;
  472.     
  473.     if( t1 >= tims.last )
  474.     return;
  475.  
  476.     nbits = t->n.vec->nbits;
  477.     start = tmpHBuff;
  478.     changes = &(tmpHBuff[ nbits ]);
  479.     strlen = (nbits + t->bdigit - 1) / t->bdigit;
  480.  
  481.       {
  482.     register hptr      h, *s;
  483.     register int       n, val;
  484.     register hptr      *ch = changes;
  485.     register TimeType  tm = tims.end;
  486.  
  487.     s = start;            /* initialize start array */
  488.     firstChange = tims.start;
  489.     for( n = nbits - 1; n >= 0; n-- )
  490.       {
  491.         h = s[n] = t->cache[n].wind;
  492.         val = h->val;
  493.         while( h->time < tm and h->val == val )
  494.         NEXTH( h, h );
  495.         ch[n] = h;
  496.       }
  497.       }
  498.  
  499.     mid = (t->top + t->bot) / 2;
  500.     x2 = TimeToX( t2 );
  501.     x1 = TimeToX( firstChange );
  502.  
  503.     while( t1 < t2 )
  504.       {
  505.       {                /* find nearest change in time */
  506.         register hptr  *ch;
  507.         register int   n;
  508.  
  509.         t1 = tims.end + 1;
  510.         for( ch = changes, n = nbits - 1; n >= 0; n-- )
  511.           {
  512.         if( ch[n]->time < t1 )
  513.             t1 = ch[n]->time;
  514.           }
  515.       }
  516.  
  517.     if( t1 <= t2 )            /* change before t2 => draw it */
  518.       {
  519.         x2 = TimeToX( t1 );
  520.         if( x2 - x1 > 3 )
  521.           {
  522.         HLine( x1 + 2, x2 - 2, t->top, WHITE );
  523.         HLine( x1 + 2, x2 - 2, t->bot, WHITE );
  524.         xx = 2;
  525.           }
  526.         else
  527.         xx = (x2 - x1 - 2);
  528.  
  529.         VLine( x2, t->bot - 2, t->top + 2, WHITE );
  530.         if( x2 > traceBox.left + 1 )
  531.           {
  532.         Line( x2 - xx, t->top, x2, t->top + 2 );
  533.         Line( x2 - xx, t->bot, x2, t->bot - 2 );
  534.           }
  535.         if( x2 < traceBox.right - 1 )
  536.           {
  537.         Line( x2, t->top + 2, x2 + 2, t->top );
  538.         Line( x2, t->bot - 2, x2 + 2, t->bot );
  539.           }
  540.       }
  541.     else                /* change after t2 */
  542.       {
  543.         register TimeType  tm;
  544.  
  545.         tm = min( t1, min( tims.end, tims.last ) );
  546.         x2 = TimeToX( tm );
  547.         HLine( x1 + 2, x2, t->top, WHITE );
  548.         HLine( x1 + 2, x2, t->bot, WHITE );
  549.       }
  550.  
  551.      {
  552.         char  *str;
  553.         str = HistToStr( start, nbits, t->bdigit, 1 );
  554.         StrCenter( str, strlen, x1, x2, mid, WHITE, BLACK );
  555.       }
  556.  
  557.       {
  558.         register hptr      h;
  559.         register hptr      *ch, *s;
  560.         register int       n, val;
  561.         register TimeType  tm = tims.end;
  562.  
  563.         for( s = start, ch = changes, n = nbits - 1; n >= 0; n-- )
  564.           {
  565.         if( ch[n]->time == t1 )
  566.           {
  567.             h = s[n] = ch[n];
  568.             val = h->val;
  569.             while( h->time < tm and h->val == val )
  570.             NEXTH( h, h );
  571.             ch[n] = h;
  572.           }
  573.           }
  574.       }
  575.     x1 = x2;
  576.       }
  577.   }
  578.  
  579.  
  580. private void PrintLegend()
  581.   {
  582.     int       i, nbits;
  583.     TraceEnt  *t;
  584.  
  585.     fprintf( psout, "/GX %d  def\n", PSX( namesBox.right + 25 ) );
  586.     fprintf( psout, "/GY %d  def\n", BANNER_BOT - 2 * (FSIZE + 3)  );
  587.     fprintf( psout, "(Legend:) 4 %d SL\n", BANNER_BOT - FSIZE - 2 );
  588.     fprintf( psout, "/FSIZE %d def FSIZE SF\n", LEGFSIZE );
  589.  
  590.     for( i = traces.disp, t = traces.first; i != 0; i--, t = t->next )
  591.       {
  592.     if( t->vector )
  593.       {
  594.         for( nbits = t->n.vec->nbits - 1; nbits >= 0; nbits-- )
  595.         psString( t->n.vec->nodes[nbits]->nname, 1000 );
  596.         nbits = t->n.vec->nbits;
  597.       }
  598.     else
  599.       {
  600.         psString( t->n.nd->nname, 1000 );
  601.         nbits = 1;
  602.       }
  603.     psString( t->name, 1000 );
  604.     fprintf( psout, "%d LE\n", nbits );
  605.       }
  606.   }
  607.  
  608.  
  609.  
  610. WritePreamble()
  611.   {
  612.     static char defs[] = "%!\n\
  613. /MSAVE { /mStat save def } def\n\
  614. /MRESTORE { mStat restore } def\n\
  615. /SET { exch def } def\n\
  616. /SF { /wi SET theFont [wi 0 0 FSIZE 0 0] makefont setfont } def\n\
  617. /L { newpath moveto lineto stroke } def\n\
  618. /VL { 2 index exch L } def\n\
  619. /HL { 1 index L } def\n\
  620. /BOX { /@yb SET /@xb SET /@yt SET /@xt SET newpath\n\
  621.  @xb @yb moveto @xb @yt lineto @xt @yt lineto @xt @yb lineto closepath } def\n\
  622. /SL { moveto show } def\n\
  623. /SR { exch dup /@xr SET 2 index stringwidth pop sub dup\n\
  624.  0 le { pop 0 @xr 3 -1 roll SC } { exch FSIZE 2 div sub moveto show }\n\
  625.  ifelse } def\n\
  626. /SCP { /@s SET @s stringwidth pop /@sw SET @sw 2 div sub\n\
  627.  dup @sw add maxX gt { pop maxX @sw sub } if exch moveto @s show } def\n\
  628. /SC { FSIZE 2 div sub /@y SET /@x2 SET /@x1 SET /@s SET\n\
  629.  /@l @x2 @x1 sub def /@x @x1 @x2 add 2 div def\n\
  630.  /@w @s stringwidth pop def @l @w gt\n\
  631.  { @y @x @s SCP }\n\
  632.  { @l FSIZE mul @w 1 add div dup MINFSIZE lt\n\
  633.  { pop } { /svf currentfont def SF @y @x @s SCP svf setfont } ifelse }ifelse\n\
  634. } def\n\
  635. /LE { exch GX GY FSIZE 2 div add SR /@x GX def\n\
  636.  { dup stringwidth pop /@w SET /@x @x FSIZE add def @x @w add\n\
  637.  720 ge { /@x GX FSIZE add def /GY GY FSIZE 2 add sub def } if\n\
  638.  @x GY SL /@x @x @w add def } repeat /GY GY FSIZE 4 add sub def } def\n\
  639. ";
  640.     /* print data and procedure definitions */
  641.     fprintf( psout, "%s", defs );
  642.     fprintf( psout, "/FSIZE %d def /MINFSIZE %d def ", FSIZE, MINFSIZE );
  643.     fprintf( psout, "/maxX %d def\n", PSX( traceBox.right ) );
  644.     /* Switch to landscape mode */
  645.     fprintf( psout, "%d 0 translate\n", 17 * PS_UNITS / 2 );
  646.     fprintf( psout, "90 rotate\n" );
  647.     fprintf( psout, "%d %d", XMARGIN, YMARGIN + TIMES_HEIGHT -
  648.       PSY( traceBox.bot) );
  649.     fprintf( psout, " translate\n" );
  650.     fprintf( psout, "1 setlinecap 0.6 setlinewidth \n" );
  651.     /* Set up text font */
  652.     fprintf( psout,"/theFont /Helvetica findfont def FSIZE SF\n");
  653.   }
  654.